// EJAnnoView.cpp : implementation file
//

#include "stdafx.h"
#include "EJWork.h"
#include "EJAnnoView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CEJAnnoView

IMPLEMENT_DYNCREATE(CEJAnnoView, CView)

CEJAnnoView::CEJAnnoView()
{
    ZeroMemory( &m_bmi, sizeof( BITMAPINFO ) );
    m_bmp = NULL;
	m_rcDisp.SetRectEmpty();
	m_dwImageLength = 0;

	m_nOper = OPER_NONE;
	m_nHover = HIT_OUTSIDE;
	
	m_bHasFocus = 0;
	m_rcFocus.SetRectEmpty();
	m_bPressed = FALSE;
	m_nOperAnno = 0xFF;
}

CEJAnnoView::~CEJAnnoView()
{
	if (m_bmp)
	{
		delete[] m_bmp;
		m_bmp = NULL;
	}
}


BEGIN_MESSAGE_MAP(CEJAnnoView, CView)
	//{{AFX_MSG_MAP(CEJAnnoView)
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_WM_ERASEBKGND()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_SETCURSOR()
	ON_WM_KEYUP()
	ON_WM_SIZE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CEJAnnoView drawing

void CEJAnnoView::DrawImage(CDC* pDC)
{
	CRect rcBound;
    CRect rc;
	CRect mask[4];
	long w,h;

	CEJData& ejd = theApp.ejd;
	CEJPage& page = ejd.page[theApp.pageInView];
	SIZE sizes = page.size;
	
	pDC->SelectStockObject(BLACK_PEN);
	pDC->SelectStockObject(NULL_BRUSH);
	
    GetClientRect(&rcBound);

//	pDC->FillSolidRect(&rcBound,RGB(255,255,255));
	
	if (sizes.cx > sizes.cy)
	{
		w = rcBound.Width();
		h = (double)w/(double)sizes.cx*(double)sizes.cy;
		rc.left = rcBound.left;
		rc.top = rcBound.top + (rcBound.Height()-h)/2;
	}
	else
	{
		h = rcBound.Height();
		w = (double)h/(double)sizes.cy*(double)sizes.cx;
		rc.top = rcBound.top;
		rc.left = rcBound.left + (rcBound.Width()-w)/2;
	}
	rc.right = rc.left + w;//sizes.cx;
	rc.bottom = rc.top + h;//sizes.cy;
	m_rcDisp = rc;

	// left
	mask[0].left = 0;
	mask[0].right = m_rcDisp.left;
	mask[0].top = rcBound.top;
	mask[0].bottom = rcBound.bottom;
	// right
	mask[1].left = m_rcDisp.right;
	mask[1].right = rcBound.right;
	mask[1].top = rcBound.top;
	mask[1].bottom = rcBound.bottom;
	// top
	mask[2].left = rcBound.left;
	mask[2].right = rcBound.right;
	mask[2].top = rcBound.top;
	mask[2].bottom = m_rcDisp.top;
	// bottom
	mask[3].left = rcBound.left;
	mask[3].right = rcBound.right;
	mask[3].top = m_rcDisp.bottom;
	mask[3].bottom = rcBound.bottom;
	
	if (m_bmp)
	{
		pDC->FillSolidRect(&mask[0],RGB(255,255,255));
		pDC->FillSolidRect(&mask[1],RGB(255,255,255));
		pDC->FillSolidRect(&mask[2],RGB(255,255,255));
		pDC->FillSolidRect(&mask[3],RGB(255,255,255));

		pDC->SetStretchBltMode(HALFTONE);
		::StretchDIBits( pDC->m_hDC,
			m_rcDisp.left, m_rcDisp.top, m_rcDisp.Width(), m_rcDisp.Height(),
			0, 0, sizes.cx, sizes.cy,
			m_bmp, &m_bmi, DIB_RGB_COLORS, SRCCOPY );

		pDC->Rectangle(&m_rcDisp);
	}
	else
	{
		pDC->FillSolidRect(&rcBound,RGB(255,255,255));
	}
	
}

void CEJAnnoView::DrawAnnos(CDC* pDC)
{
	WORD i;
	CRect r;
	CEJData& ejd = theApp.ejd;
	CEJPage& page = ejd.page[theApp.pageInView];

	pDC->SelectStockObject(NULL_BRUSH);
	
	pDC->SetROP2(R2_COPYPEN);
	for(i = 0;i<page.num;i++)
	{
		DrawAnno(pDC,page,i,page.anno[i],RGB(128,128,192),RGB(0,0,128));
	}

	if (m_nOperAnno < page.num)
	{
		DrawAnno(pDC,page,m_nOperAnno,page.anno[m_nOperAnno],RGB(192,192,10),RGB(10,10,192));
	}
}

void CEJAnnoView::DrawAnno(CDC* pDC,CEJPage& page,WORD index,CEJAnno& anno,COLORREF c1,COLORREF c2)
{
	int i;
	CRect r;
	CRect textBox;
	CString str;
	CSize sz;
	CFont* pf;

	CPen p1(PS_SOLID,1,c1);
	CPen p2(PS_SOLID,1,c2);
	CPen *pOldPen = NULL;
	
//	page.Page2Disp(m_rcDisp,anno.box,r);
	
	pDC->SetROP2(R2_COPYPEN);
	pOldPen = pDC->SelectObject(&p1);
//	pDC->Rectangle(&r);

//	if (anno.boxInView.IsRectEmpty())
//	{
		page.Page2Disp(m_rcDisp,anno);
//	}
	pDC->Rectangle(&anno.boxInView);

	for(i = 0;i<8;i++)
	{
		pDC->Rectangle(&anno.gripInView[i]);
	}

	pDC->SelectObject(pOldPen);

	r.InflateRect(1,1,1,1);

	pOldPen = pDC->SelectObject(&p2);
	pDC->Rectangle(&r);
	pDC->SelectObject(pOldPen);

	p1.DeleteObject();
	p2.DeleteObject();


	pf = pDC->SelectObject(&m_font);

	str.Format("%d",index+1);
	sz = pDC->GetTextExtent(str);
	pDC->SetTextColor(c1);
	pDC->SetBkColor(c2);

	textBox.left = anno.boxInView.left + 8;
	textBox.top = anno.boxInView.top - sz.cy/2;
	textBox.right = textBox.left + sz.cx + 4;
	textBox.bottom = textBox.top + sz.cy;

	pDC->FillSolidRect(&textBox,c2);
	pDC->DrawText(str,&textBox,DT_CENTER|DT_VCENTER);

	pDC->SelectObject(pf);
	
}

void CEJAnnoView::OnDraw(CDC* pDC)
{
	DrawImage(pDC);

	if (theApp.oper==OPER_CONTENT)
	{
		DrawAnnos(pDC);
	}
}

/////////////////////////////////////////////////////////////////////////////
// CEJAnnoView diagnostics

#ifdef _DEBUG
void CEJAnnoView::AssertValid() const
{
	CView::AssertValid();
}

void CEJAnnoView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CEJAnnoView message handlers

void CEJAnnoView::Refresh()
{
	CEJData& ejd = theApp.ejd;
	CEJPage& page = ejd.page[theApp.pageInView];

	page.LoadJPEG(ejd.baseDir);

	BYTE* data = page.pix;
	SIZE sizes = page.size;
	int nChannels = page.chnls;
	
	BITMAPINFOHEADER& bih = m_bmi.bmiHeader;
    ::ZeroMemory( &bih, sizeof( BITMAPINFOHEADER ) );
	
    bih.biSize        = sizeof( BITMAPINFOHEADER );
    bih.biWidth       = sizes.cx;
    bih.biHeight      = -sizes.cy;
    bih.biCompression = BI_RGB;
    bih.biPlanes      = 1;
    switch(nChannels)
    {
    case 3:
		bih.biBitCount = 24;
		break;
		
    case 4:
		bih.biBitCount = 32;
		break;
		
    default:
		TRACE("Unsupported number of channels!\n");
		break;
    }

//    if( m_bmp != NULL )
//		delete[] m_bmp;
    int pad = IJL_DIB_PAD_BYTES(sizes.cx,nChannels);
    int imageSize = (sizes.cx * nChannels + pad) * sizes.cy;

	if (imageSize != m_dwImageLength)
	{
		m_dwImageLength = imageSize;
		if (m_bmp!=NULL)
		{
			delete[] m_bmp;
			m_bmp = NULL;
		}
	}
	if (m_bmp==NULL)
	{
	    m_bmp = new BYTE[m_dwImageLength];
	}

    ::ZeroMemory(m_bmp,imageSize);
    ::CopyMemory(m_bmp,data,imageSize);

	Invalidate();

	ejd.Unload(theApp.pageInView);

	m_bHasFocus = FALSE;
}
/*
void CEJAnnoView::OnSetAnno(WORD index,const CRect& rc)
{
	CRect r;
	
	CEJData& ejd = theApp.ejd;
	CEJPage& page = ejd.page[theApp.pageInView];
	CEJAnno& anno = page.anno[index];

	page.Disp2Page(m_rcDisp,rc,anno.box);
}
*/

void CEJAnnoView::OnHover(CDC* pDC,const CPoint& pt)
{
	BYTE hitIndex = HIT_OUTSIDE;
	CEJPage& page = theApp.ejd.page[theApp.pageInView];

	if (m_nOperAnno < page.num)
	{
		CEJAnno& anno = page.anno[m_nOperAnno];

		hitIndex = anno.HitTest(pt);
	}

	if (m_nHover!=hitIndex)
	{
		m_nHover = hitIndex;
	}
}

void CEJAnnoView::OnBeginAdd()
{
	m_nOper = OPER_ADD;
}

void CEJAnnoView::OnDuringAdd(const CPoint& pt)
{
	m_rcFocus.SetRect(m_ptPressed,pt);
	m_rcFocus.NormalizeRect();

	m_rcFocus.left = max(m_rcFocus.left,m_rcDisp.left);
	m_rcFocus.right = min(m_rcFocus.right,m_rcDisp.right);
	m_rcFocus.top = max(m_rcFocus.top,m_rcDisp.top);
	m_rcFocus.bottom = min(m_rcFocus.bottom,m_rcDisp.bottom);
}

void CEJAnnoView::OnEndAdd()
{
	CRect r;
	CEJData& ejd = theApp.ejd;
	CEJPage& page = ejd.page[theApp.pageInView];
	CMainFrame* mf = (CMainFrame *)theApp.m_pMainWnd;
	CEJEditView* ev = mf->GetEditView();
	
	if (m_rcFocus.Width()>10&&m_rcFocus.Height()>10)
	{
		page.Disp2Page(m_rcDisp,m_rcFocus,r);
		page.AddAnno(m_rcDisp,r);
		ev->Refresh();
		theApp.modified = 1;
	}
}

void CEJAnnoView::OnBeginSelect(WORD index,BYTE gripIndex)
{
	CEJData& ejd = theApp.ejd;
	CEJPage& page = ejd.page[theApp.pageInView];

	m_nOper = OPER_MOVE;
	if (m_nOperAnno == index)
	{
		if (gripIndex >= HIT_LEFTTOP && gripIndex<=HIT_LEFT)
		{
			m_nOperGrip = gripIndex;
			m_nOper = OPER_RESIZE;
		}
	}
	m_nOperAnno = index;
	m_rcFocus.CopyRect(&page.anno[m_nOperAnno].boxInView);
}

void CEJAnnoView::OnDuringMove(const CPoint& pt)
{
	CRect rc;
	long dx,dy;

	dx = pt.x - m_ptDrag.x;
	dy = pt.y - m_ptDrag.y;
	
	rc.CopyRect(&m_rcFocus);
	rc.OffsetRect(dx,dy);

	if (rc.left < m_rcDisp.left)
	{
		rc.left = m_rcDisp.left;
		rc.right = rc.left + m_rcFocus.Width();
	}
	if (rc.right >= m_rcDisp.right)
	{
		rc.right = m_rcDisp.right-1;
		rc.left = rc.right - m_rcFocus.Width();
	}
	if (rc.top<m_rcDisp.top)
	{
		rc.top = m_rcDisp.top;
		rc.bottom = rc.top + m_rcFocus.Height();
	}
	if (rc.bottom>=m_rcDisp.bottom)
	{
		rc.bottom = m_rcDisp.bottom-1;
		rc.top = rc.bottom - m_rcFocus.Height();
	}
	m_rcFocus.CopyRect(&rc);
	m_ptDrag = pt;
}

void CEJAnnoView::OnDuringResize(const CPoint& pt)
{
	CRect rc;
	long x = pt.x;
	long y = pt.y;

	rc.CopyRect(&m_rcFocus);
	
	x = max(m_rcDisp.left,x);
	x = min(m_rcDisp.right,x);

	y = max(m_rcDisp.top,y);
	y = min(m_rcDisp.bottom,y);
	
	switch(m_nOperGrip)
	{
	case HIT_LEFTTOP:
		rc.left = x;
		rc.top = y;
		break;
	case HIT_RIGHTTOP:
		rc.right = x;
		rc.top = y;
		break;
	case HIT_RIGHTBOTTOM:
		rc.right = x;
		rc.bottom = y;
		break;
	case HIT_LEFTBOTTOM:
		rc.left = x;
		rc.bottom = y;
		break;
	case HIT_TOP:
		rc.top = y;
		break;
	case HIT_RIGHT:
		rc.right = x;
		break;
	case HIT_BOTTOM:
		rc.bottom = y;
		break;
	case HIT_LEFT:
		rc.left = x;
		break;
	default:
		break;
	}

	m_rcFocus.CopyRect(&rc);
}

void CEJAnnoView::OnEndSelect(const CPoint& pt)
{
	CRect rc;
	CSize sz = pt - m_ptPressed;
	CEJData& ejd = theApp.ejd;
	CEJPage& page = ejd.page[theApp.pageInView];
	CEJAnno& anno = page.anno[m_nOperAnno];
	
	if (abs(sz.cx)<=3 && abs(sz.cy)<=3)	// select
	{
//		CMainFrame* mf = (CMainFrame *)theApp.m_pMainWnd;
//		CEJEditView* ev = mf->GetEditView();
//		ev->OnAnnoChanged(index);
	}
	else	// move
	{
		m_rcFocus.NormalizeRect();
		page.Disp2Page(m_rcDisp,m_rcFocus,anno.box);
		page.Page2Disp(m_rcDisp,anno);
		theApp.modified = 1;
	}
}

void CEJAnnoView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	WORD index;
	BYTE hitIndex;
	CEJData& ejd = theApp.ejd;
	CEJPage& page = ejd.page[theApp.pageInView];
	
	CView::OnLButtonDown(nFlags, point);
	
	if (theApp.oper==OPER_CONTENT)
	{
		m_bPressed = TRUE;
		m_ptPressed = point;
		m_ptDrag = point;
		
		index = page.HitTest(m_rcDisp,point,&hitIndex);
		if (index<page.num)
		{
			OnBeginSelect(index,hitIndex);
		}
		else
		{
			OnBeginAdd();
		}
	}
}

void CEJAnnoView::OnLButtonUp(UINT nFlags, CPoint point) 
{
	CDC* pDC = GetDC();
	CView::OnLButtonUp(nFlags, point);
	
	if (m_bHasFocus)
	{
		DrawFocus(pDC);
		m_bHasFocus = FALSE;
	}
	switch(m_nOper)
	{
	case OPER_ADD:
		OnEndAdd();
		break;
	case OPER_MOVE:
	case OPER_RESIZE:
		OnEndSelect(point);
		break;
	default:
		break;
	}

	m_bPressed = FALSE;

	ReleaseDC(pDC);

	Invalidate();
	m_nOper = OPER_NONE;
}

void CEJAnnoView::OnMouseMove(UINT nFlags, CPoint point) 
{
	CRect rc;
	CDC* pDC = GetDC();
	CView::OnMouseMove(nFlags, point);

	if (m_bPressed)
	{
		if (m_bHasFocus)
		{
			DrawFocus(pDC);
		}
		m_bHasFocus = TRUE;
		switch(m_nOper)
		{
		case OPER_ADD:
			OnDuringAdd(point);
			break;
		case OPER_MOVE:
			OnDuringMove(point);
			break;
		case OPER_RESIZE:
			OnDuringResize(point);
			break;
		default:
			break;
		}
		DrawFocus(pDC);		
	}
	else
	{
		OnHover(pDC,point);
	}

	ReleaseDC(pDC);
}

void CEJAnnoView::DrawFocus(CDC* pDC)
{
	CPen pen(PS_SOLID,1,RGB(0,255,255));
	CPen *pOldPen = pDC->SelectObject(&pen);
	pDC->SelectStockObject(NULL_BRUSH);
	pDC->SetROP2(R2_XORPEN);
	
	pDC->Rectangle(&m_rcFocus);
	
	pDC->SetROP2(R2_COPYPEN);
	pDC->SelectObject(pOldPen);
	pen.DeleteObject();
}

BOOL CEJAnnoView::OnEraseBkgnd(CDC* pDC) 
{
	return FALSE;
}

void CEJAnnoView::OnInitialUpdate() 
{
	LOGFONT lf;

	CView::OnInitialUpdate();

	memset(&lf,0,sizeof(lf));
	
	strcpy(lf.lfFaceName,"Tahoma");
	lf.lfHeight = 16;
	lf.lfWeight = FW_BOLD;
	m_font.CreateFontIndirect(&lf);
}

void CEJAnnoView::OnLButtonDblClk(UINT nFlags, CPoint point) 
{	
	WORD index;
	CAnnoDialog dlg;

	CView::OnLButtonDblClk(nFlags, point);

	CEJData& ejd = theApp.ejd;
	CEJPage& page = ejd.page[theApp.pageInView];
	CMainFrame* mf = (CMainFrame *)theApp.m_pMainWnd;
	CEJEditView* ev = mf->GetEditView();
	
	index = page.HitTest(m_rcDisp,point,NULL);

	if (index<page.num && index==m_nOperAnno)
	{
		dlg.page = &page;
		dlg.annoIndex = m_nOperAnno;
		dlg.m_annoWnd.page = &page;
		dlg.m_annoWnd.bmp = m_bmp;
		dlg.m_annoWnd.bmi = &m_bmi;
		dlg.m_annoWnd.index = m_nOperAnno;
		dlg.DoModal();

		if (dlg.m_bModified)
		{
			ev->Refresh();
			theApp.modified = 1;
		}
	}
}

BOOL CEJAnnoView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{
	switch(m_nHover)
	{
	case HIT_INSIDE:
		SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEALL));
		break;
	case HIT_LEFTTOP:
	case HIT_RIGHTBOTTOM:
		SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENWSE));
		break;
	case HIT_RIGHTTOP:
	case HIT_LEFTBOTTOM:
		SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENESW));
		break;
	case HIT_LEFT:
	case HIT_RIGHT:
		SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
		break;
	case HIT_TOP:
	case HIT_BOTTOM:
		SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
		break;
	case HIT_OUTSIDE:
	default:
		SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
		break;
	}

	return TRUE;
}

void CEJAnnoView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	CMainFrame* mf = (CMainFrame *)theApp.m_pMainWnd;
	CEJEditView* ev = mf->GetEditView();

	CView::OnKeyUp(nChar, nRepCnt, nFlags);
	CEJPage& page = theApp.ejd.page[theApp.pageInView];
	switch(nChar)
	{
	case VK_DELETE:
		if (m_nOperAnno>=0 && m_nOperAnno<page.num)
		{
			page.DelAnno(m_nOperAnno);
			Refresh();
			ev->Refresh();
			theApp.modified = 1;
		}
		break;
	default:
		break;
	}
}

void CEJAnnoView::OnSize(UINT nType, int cx, int cy) 
{
//	CRect rcBound;
//	CEJData& ejd = theApp.ejd;
//	CEJPage& page = ejd.page[theApp.pageInView];
//	SIZE sizes = page.size;
	
	CView::OnSize(nType, cx, cy);

//	if (m_hWnd && m_bmp)
//	{
//		GetClientRect(&rcBound);
//		
//		if (sizes.cx > sizes.cy)
//		{
//			w = rcBound.Width();
//			h = (double)w/(double)sizes.cx*(double)sizes.cy;
//			rc.left = rcBound.left;
//			rc.top = rcBound.top + (rcBound.Height()-h)/2;
//		}
//		else
//		{
//			h = rcBound.Height();
//			w = (double)h/(double)sizes.cy*(double)sizes.cx;
//			rc.top = rcBound.top;
//			rc.left = rcBound.left + (rcBound.Width()-w)/2;
//		}
//		rc.right = rc.left + w;//sizes.cx;
//		rc.bottom = rc.top + h;//sizes.cy;
//		m_rcDisp = rc;
//
//	}	
}
